import csv
import requests
import re
import os
from pathlib import Path
from tkinter.messagebox import showinfo
from tkinter.filedialog import askdirectory
import tkinter as tk

def set_win_center(root, curWidth='', curHight=''):
    '''
    设置窗口大小，并居中显示
    :param root:主窗体实例
    :param curWidth:窗口宽度，非必填，默认200
    :param curHight:窗口高度，非必填，默认200
    :return:无
    '''
    if not curWidth:
        '''获取窗口宽度，默认200'''
        curWidth = root.winfo_width()
    if not curHight:
        '''获取窗口高度，默认200'''
        curHight = root.winfo_height()
    # print(curWidth, curHight)

    # 获取屏幕宽度和高度
    scn_w, scn_h = root.maxsize()
    # print(scn_w, scn_h)

    # 计算中心坐标
    cen_x = (scn_w - curWidth) / 2
    cen_y = (scn_h - curHight) / 2
    # print(cen_x, cen_y)

    # 设置窗口初始大小和位置
    size_xy = '%dx%d+%d+%d' % (curWidth, curHight, cen_x, cen_y)
    root.geometry(size_xy)

def show_readme(readme:str):
    showinfo(title="操作说明", message=readme)

def selectPath():
    path_ = askdirectory()
    entry_path.set(path_)

def is_legal(url: str, file_name: str, path: str):
    if url == "":
        return "网址不能为空！"
    if file_name == "":
        return "文件名不能为空！"
    if path == "":
        return "保存路径不能为空！"
    # 判断是否是目录且目录已经存在
    my_file = Path(path)
    if not my_file.is_dir():
        return path + "文件夹不存在，请输入合法的保存路径！"

    return ''

def url_to_csviterator(url: str):
    '''
    任务：将url对应的视频目录获取到，并返回一个迭代器；同时要在爬取过程中对网址做合法性检查。
    :param url: 要爬取的视频的网址
    :return: 迭代器
    '''

    # 爬取数据
    try:
        resp = requests.get(url)
    except Exception:
        return "您输入的网址不正确，请确保它是一个以http或https开头的哔哩哔哩网站中某视频的网址。"

    resp = requests.get(url)
    page_content = resp.text

    # 解析数据
    pattern_obj = re.compile(r'\[{"cid":.*\],"subtitle":{', re.S)
    match_obj = pattern_obj.search(page_content)
    try:
        page_content2 = match_obj.group()
    except AttributeError:
        return "您输入的网址不正确，请确保它是一个以http或https开头的哔哩哔哩网站中某视频的网址。"

    pattern_obj2 = re.compile(
        r'"page":(?P<page>.*?),.*?"part":"(?P<title>.*?)","duration":(?P<seconds>.*?),', re.S)
    csviterator = pattern_obj2.finditer(page_content2)

    return csviterator

def csviterator_to_file(file_name: str, path: str, csviterator):
    '''
    任务：把结果从迭代器中取出，并保存到指定文件中
    :param file_name: 要保存到的文件名（不含后缀）
    :param path: 要把文件保存到的目录
    :param csviterator: 迭代器
    :return: 标识结果的字符串
    '''
    try:
        f = open(path + os.sep + file_name + ".csv", mode="w", newline="")
    except FileNotFoundError:
        return "请输入合法的文件名！"  # 这种情况下处理的是用户输入的文件名不符合Windows、Mac OS等系统对文件名的要求

    csvwriter = csv.writer(f)
    csv_header = ['page', 'title', 'seconds', 'minutes', 'hours']
    csvwriter.writerow(csv_header)
    for line in csviterator:
        dict_line = line.groupdict()
        dict_line["minutes"] = round(float(dict_line["seconds"]) / 60, 2)
        dict_line['hours'] = round(float(dict_line["minutes"]) / 60, 2)
        csvwriter.writerow(dict_line.values())

    f.close()
    return "视频目录成功下载至" + path + os.sep + file_name + ".csv"

def info_clear():
    global entry_url, entry_filename, entry_path
    entry_url.delete(0, tk.END)
    entry_filename.delete(0, tk.END)
    entry_path.set("")

def info_submit(url: str, file_name: str, path: str):
    log_info = is_legal(url, file_name, path)
    print(log_info)
    if log_info == "":
        log_info = csviterator_to_file(file_name, path, url_to_csviterator(url))
    showinfo(title='提示信息', message=log_info)


readme = """
当用户输入视频网址、保存为的文件名、存储目录，本程序将会把该视频的分p目录情况，以及每集的时长情况以excel(csv)的形式保存到指定目录下。
-----------------
视频网址：请输入哔哩哔哩网站上某视频的完整网址，通常以http或https开头。示例 https://www.bilibili.com/video/BV1os411h77o
保存路径：决定了将生成的excel文件保存到您计算机中的哪个文件夹下。该文件夹需已存在在您的计算机中。建议通过右侧的”路径选择“按钮直接选择路径而非手动输入，这样可以避免不同系统的路径分割付差异所带来的的运行错误。
文件名称：决定了您的excel文件的文件名。本程序将在您选择的保存路径下创建该excel文件。（不需要添加.csv或.xls后缀，本程序将自动添加）
-----------------
例如，当输入的网址是https://www.bilibili.com/video/BV1os411h77o，文件名是C语言教程，保存路径是C:/myfile，则该网址对应的视频将被保存到C:/myfile/C语言教程.csv，可以通过MS Powerpoint或WPS演示打开该文件。
-----------------
保存后的文件有五列：
page: \t视频在目录中的序号，从1依次递增
title: \t视频的标题
hours: \t视频时长（用小时表示）
minutes: \t视频时长（用分钟表示）
seconds: \t视频时长（用秒表示）
-----------------
程序作者：王添翼(1124368866@qq.com)，因想要根据每集网课的时长确定学习日程而创作本程序。
        """

win_width = 650
win_height = 100
win = tk.Tk()
# # 设置主窗口
# win.geometry(str(win_width)+'x')
win.title('哔哩哔哩视频分p目录下载器 by 王添翼(1124368866@qq.com)')
set_win_center(win, win_width, win_height)


label_url = tk.Label(win, text="视频网址")
label_filename = tk.Label(win, text="文件名称")
label_url.grid(row=0)
label_filename.grid(row=1)
entry_width = 70
entry_url = tk.Entry(win, width=entry_width)
entry_filename = tk.Entry(win, width=entry_width)
entry_url.grid(row=0, column=1)
entry_filename.grid(row=1, column=1)

default_path = os.getcwd()

entry_path = tk.StringVar()
entry_path.set(default_path)

tk.Label(win,text = "保存路径").grid(row = 3, column = 0)
tk.Entry(win, textvariable = entry_path, width=entry_width).grid(row = 3, column = 1)
tk.Button(win, text = "路径选择", command = selectPath).grid(row = 3, column = 2)
tk.Button(win, text="点此清空", command=info_clear).grid(row = 5, column = 0)
tk.Button(win, text="点此提交", command=lambda: info_submit(entry_url.get(), entry_filename.get(), entry_path.get())).grid(row = 5, column = 2)
tk.Button(win, text = "点此查看用户必读", command = lambda: show_readme(readme)).grid(row = 5, column = 1)



win.mainloop()


